package com.app.code.util;

import cn.hutool.core.util.StrUtil;
import cn.org.rapid_framework.generator.GeneratorFacade;
import cn.org.rapid_framework.generator.GeneratorProperties;
import com.app.code.pojo.dto.SysGeneratorDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

/**
 * @author qiangt
 * @version 1.0
 * @date 2024/3/8 9:52
 * @description: 代码生成工具类
 */
@Slf4j
@Component
public class CodeUtil {

    private static String mDriver;
    private static String mUrl;
    private static String mUsername;
    private static String mPassword;
    private static String mProjectPathJava;
    private static String mProjectPathWeb;
    private static String mTemplatePath;
    private static String mTableName;
    private static String mDescription;
    private static String mPackageName;
    private static String mModuleName;
    private static String mFunctionName;
    private static String mFunctionNameUpCase;
    private static String mEntityName;
    private static String mAuthorName;
    private static String mOutRootJava;
    private static String mTemplateRootJava;
    private static String mOutRootMapper;
    private static String mTemplateRootMapper;
    private static String mOutRootApi;
    private static String mTemplateRootApi;
    private static String mOutRootViews;
    private static String mTemplateRootViews;
    @Value("${spring.datasource.dynamic.datasource.master.driver-class-name}")
    private String driver;
    @Value("${spring.datasource.dynamic.datasource.master.url}")
    private String url;
    @Value("${spring.datasource.dynamic.datasource.master.username}")
    private String username;
    @Value("${spring.datasource.dynamic.datasource.master.password}")
    private String password;
    @Value("${generator.outPath}")
    private String generatorOutPath;

    public static void startGenerator(SysGeneratorDto sysGeneratorDto) {
        mTableName = sysGeneratorDto.getTableName();
        mDescription = sysGeneratorDto.getDescription();
        mPackageName = sysGeneratorDto.getPackageName();
        mModuleName = sysGeneratorDto.getModuleName();
        mFunctionName = sysGeneratorDto.getFunctionName();
        if (StrUtil.isNotBlank(mFunctionName)) {
            if (mFunctionName.contains("/")) {
                StringBuilder stringBuilder = new StringBuilder(16);
                String[] functionNames = mFunctionName.split("/");
                stringBuilder.append(functionNames[0]);
                for (int i = 1; i < functionNames.length; i++) {
                    stringBuilder.append(functionNames[i].substring(0, 1).toUpperCase());
                    stringBuilder.append(functionNames[i].substring(1));
                }
                mFunctionNameUpCase = stringBuilder.toString();
            } else {
                mFunctionNameUpCase = mFunctionName;
            }
        }
        mEntityName = sysGeneratorDto.getEntityName();
        mAuthorName = StrUtil.isEmpty(sysGeneratorDto.getAuthorName()) ? "author" : sysGeneratorDto.getAuthorName();

        mOutRootJava = mProjectPathJava + "/cyt-" + mPackageName + "/src/main/java/com/cyt/" + mModuleName + "/";
        mTemplateRootJava = mTemplatePath + "/java";
        mOutRootMapper = mProjectPathJava + "/cyt-" + mPackageName + "/src/main/resources/mapper/" + mModuleName + "/";
        mTemplateRootMapper = mTemplatePath + "/mapper";

        mOutRootApi = mProjectPathWeb + "/src/api/" + mModuleName + "/";
        mTemplateRootApi = mTemplatePath + "/api";
        mOutRootViews = mProjectPathWeb + "/src/views/" + mModuleName + "/" + mFunctionName + "/";
        mTemplateRootViews = mTemplatePath + "/views";

        deleteGeneratorCode(sysGeneratorDto.getFrontOrBehind());
        initGeneratorProperties();
        startGeneratorCode(sysGeneratorDto.getFrontOrBehind());
    }

    private static void deleteGeneratorCode(String frontOrBehind) {
        List<File> fileList = new ArrayList<>();
        if ("1".equals(frontOrBehind)) {
            // 前端代码
            String basePath = mProjectPathWeb + "/src/api/" + mModuleName;
            fileList.add(new File((basePath + "/" + mFunctionName + ".js")));
            fileList.add(new File((basePath)));
            basePath = mProjectPathWeb + "/src/views" + mModuleName + "/" + mFunctionName;
            fileList.add(new File((basePath + "/index.vue")));
            fileList.add(new File((basePath + "/form.vue")));
            fileList.add(new File((basePath)));
        } else if ("2".equals(frontOrBehind)) {
            // 后端代码
            String basePath = mProjectPathJava + "/cyt-" + mPackageName + "/src/main/java/com/cyt/" + mModuleName;
            fileList.add(new File((basePath + "/controller/" + mEntityName + "Controller.java")));
            fileList.add(new File((basePath + "/controller")));
            fileList.add(new File((basePath + "/service/" + mEntityName + "Service.java")));
            fileList.add(new File((basePath + "/service")));
            fileList.add(new File((basePath + "/service/impl/" + mEntityName + "ServiceImpl.java")));
            fileList.add(new File((basePath + "/service/impl")));
            fileList.add(new File((basePath + "/dao/" + mEntityName + "Dao.java")));
            fileList.add(new File((basePath + "/dao")));
            fileList.add(new File((basePath + "/domain/dto/" + mEntityName + "Dto.java")));
            fileList.add(new File((basePath + "/domain/dto")));
            fileList.add(new File((basePath + "/domain/po/" + mEntityName + ".java")));
            fileList.add(new File((basePath + "/domain/po")));
            fileList.add(new File((basePath + "/domain/vo/excel/" + mEntityName + "ExportVo.java")));
            fileList.add(new File((basePath + "/domain/vo/excel/" + mEntityName + "ImportVo.java")));
            fileList.add(new File((basePath + "/domain/vo/excel/")));
            fileList.add(new File((basePath + "/domain/vo/" + mEntityName + "Vo.java")));
            fileList.add(new File((basePath + "/domain/vo")));
            fileList.add(new File((basePath + "/domain")));
            fileList.add(new File((basePath)));
            basePath = mProjectPathJava + "/cyt-" + mPackageName + "/src/main/resources/mapper/" + mModuleName;
            fileList.add(new File((basePath + "/" + mEntityName + "Mapper.xml")));
            fileList.add(new File((basePath)));
        }
        deleteFileOrDirectory(fileList);
    }

    private static void initGeneratorProperties() {
        GeneratorProperties.setProperty("jdbc_driver", mDriver);
        GeneratorProperties.setProperty("jdbc_url", mUrl);
        GeneratorProperties.setProperty("jdbc_username", mUsername);
        GeneratorProperties.setProperty("jdbc_password", mPassword);
        GeneratorProperties.setProperty("java_typemapping.java.lang.Byte", "Integer");
        GeneratorProperties.setProperty("java_typemapping.java.lang.Short", "Integer");
        GeneratorProperties.setProperty("java_typemapping.java.lang.Integer", "Integer");
        GeneratorProperties.setProperty("java_typemapping.java.lang.Long", "BigDecimal");
        GeneratorProperties.setProperty("java_typemapping.java.lang.Float", "Float");
        GeneratorProperties.setProperty("java_typemapping.java.lang.Double", "Double");
        GeneratorProperties.setProperty("java_typemapping.java.lang.String", "String");
        GeneratorProperties.setProperty("java_typemapping.java.sql.Date", "Date");
        GeneratorProperties.setProperty("java_typemapping.java.sql.Timestamp", "Date");
        GeneratorProperties.setProperty("description", mDescription);
        GeneratorProperties.setProperty("moduleName", mModuleName);
        GeneratorProperties.setProperty("functionName", mFunctionName);
        GeneratorProperties.setProperty("functionNameUpCase", mFunctionNameUpCase);
        GeneratorProperties.setProperty("entityName", mEntityName);
        GeneratorProperties.setProperty("authorName", mAuthorName);
    }

    private static void startGeneratorCode(String frontOrBehind) {
        try {
            GeneratorFacade generatorFacade;
            if ("1".equals(frontOrBehind)) {
                GeneratorProperties.setProperty("outRoot", mOutRootApi);
                generatorFacade = new GeneratorFacade();
                generatorFacade.getGenerator().setTemplateRootDir(mTemplateRootApi);
                generatorFacade.generateByTable(mTableName);
                GeneratorProperties.setProperty("outRoot", mOutRootViews);
                generatorFacade = new GeneratorFacade();
                generatorFacade.getGenerator().setTemplateRootDir(mTemplateRootViews);
                generatorFacade.generateByTable(mTableName);
            } else {
                GeneratorProperties.setProperty("outRoot", mOutRootJava);
                generatorFacade = new GeneratorFacade();
                generatorFacade.getGenerator().setTemplateRootDir(mTemplateRootJava);
                generatorFacade.generateByTable(mTableName);
                GeneratorProperties.setProperty("outRoot", mOutRootMapper);
                generatorFacade = new GeneratorFacade();
                generatorFacade.getGenerator().setTemplateRootDir(mTemplateRootMapper);
                generatorFacade.generateByTable(mTableName);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    private static void deleteFileOrDirectory(List<File> fileList) {
        for (File file : fileList) {
            if (file.exists() && file.isFile()) {
                boolean result = file.delete();
                while (!result) {
                    if (file.exists()) {
                        System.gc();
                        result = file.delete();
                    }
                }
            }
        }
        for (File file : fileList) {
            if (file.exists() && file.isDirectory()) {
                File[] files = file.listFiles();
                if (files != null && files.length == 0) {
                    boolean result = file.delete();
                    while (!result) {
                        if (file.exists()) {
                            System.gc();
                            result = file.delete();
                        }
                    }
                }
            }
        }
    }

    @PostConstruct
    public void init() {
        CodeUtil.mDriver = driver;
        CodeUtil.mUrl = url;
        CodeUtil.mUsername = username;
        CodeUtil.mPassword = password;
        CodeUtil.mProjectPathJava = generatorOutPath + "/java_code";
        CodeUtil.mProjectPathWeb = generatorOutPath + "/web_code";
        CodeUtil.mTemplatePath = "classpath:template";
    }
}
